<!DOCTYPE html>
<html>
<head>
    <!--
        Adapted from https://docs.mapbox.com/mapbox-gl-js/example/3d-buildings/
    -->
    <meta charset='utf-8' />
    <title>Blue Pill Geolocation</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.1/mapbox-gl.js'></script>
    <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.1/mapbox-gl.css' rel='stylesheet' />
    <style>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }
    </style>
</head>
<body>

<div id='map'></div>

<svg id='actual_location' width="54px" height="82px" viewBox="0 0 54 82" text-anchor="middle" style="font: 12px sans-serif">
    <g fill-rule="nonzero">
        <g transform="translate(14, 12)" fill="#FFFFFF" dominant-baseline="central">
            <text style="font: 12px sans-serif">Actual Location</text>
        </g>        
    </g>
</svg>

<!--  Location Marker  -->
<svg id='marker' width="54px" height="82px" viewBox="0 0 54 82" text-anchor="middle" style="font: 12px sans-serif">
    <g fill-rule="nonzero" transform="scale(2, 2)">
        <g transform="translate(3.0, 29.0)" fill="#000000">
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="10.5" ry="5.25002273"></ellipse>
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="10.5" ry="5.25002273"></ellipse>
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="9.5" ry="4.77275007"></ellipse>
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="8.5" ry="4.29549936"></ellipse>
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="7.5" ry="3.81822308"></ellipse>
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="6.5" ry="3.34094679"></ellipse>
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="5.5" ry="2.86367051"></ellipse>
            <ellipse opacity="0.04" cx="10.5" cy="5.80029008" rx="4.5" ry="2.38636864"></ellipse>
        </g>
        <g opacity="0.8" fill="#803FB1CE">
            <path
                d="M27,13.5 C27,19.074644 20.250001,27.000002 14.75,34.500002 C14.016665,35.500004 12.983335,35.500004 12.25,34.500002 C6.7499993,27.000002 0,19.222562 0,13.5 C0,6.0441559 6.0441559,0 13.5,0 C20.955844,0 27,6.0441559 27,13.5 Z">
            </path>
        </g>
        <g opacity="0.25" fill="#000000">
            <path
                d="M13.5,0 C6.0441559,0 0,6.0441559 0,13.5 C0,19.222562 6.7499993,27 12.25,34.5 C13,35.522727 14.016664,35.500004 14.75,34.5 C20.250001,27 27,19.074644 27,13.5 C27,6.0441559 20.955844,0 13.5,0 Z M13.5,1 C20.415404,1 26,6.584596 26,13.5 C26,15.898657 24.495584,19.181431 22.220703,22.738281 C19.945823,26.295132 16.705119,30.142167 13.943359,33.908203 C13.743445,34.180814 13.612715,34.322738 13.5,34.441406 C13.387285,34.322738 13.256555,34.180814 13.056641,33.908203 C10.284481,30.127985 7.4148684,26.314159 5.015625,22.773438 C2.6163816,19.232715 1,15.953538 1,13.5 C1,6.584596 6.584596,1 13.5,1 Z">
            </path>
        </g>
        <g transform="translate(6.0, 7.0)" fill="#FFFFFF"></g>
        <!--
        <g transform="translate(8.0, 8.0)">
            <circle fill="#000000" opacity="0.25" cx="5.5" cy="5.5" r="5.4999962"></circle>
            <circle fill="#FFFFFF" opacity="0.5" cx="5.5" cy="5.5" r="5.4999962"></circle>
        </g>
        <g transform="translate(14, 12)" fill="#FFFFFF" dominant-baseline="central">
            <text id="value_text" style="font: 12px sans-serif"></text>
        </g>
        -->
    </g>
</svg>

<!--  Temperature Label  -->
<svg id='label' width="60px" height="82px" viewBox="0 0 60 82" text-anchor="middle" style="font: 12px sans-serif">
    <g fill-rule="nonzero" transform="scale(2, 2)">
        <g transform="translate(14, 12)" fill="#FFFFFF" dominant-baseline="central">
            <text id="label_text" style="font: 12px sans-serif"></text>
        </g>
    </g>
</svg>

</body>
<!-- Load the turf.js library for computing GeoJSON geometries -->
<script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
<!-- token.js contains:
    var MAPBOX_TOKEN = 'YOUR_MAPBOX_TOKEN'; 
-->
<script src='token.js'></script>
<script>
mapboxgl.accessToken = MAPBOX_TOKEN;
var ACCURACY_LAYER_ID = 'accuracy';

var device = null;
var tmp = null;
var lat = 1.2730656999999999;
var lng = 103.8096223;
var accuracy = 100;

var zoom = 17;
var pitch = 45;
var bearing = -17.6;
    
//  Create the location marker.
var markerSvg = document.getElementById('marker');
var marker = new mapboxgl.Marker({ 
    element: markerSvg,
    offset: [0, -27],  //  We have enlarged the icon by 2, so shift the y offset.
}).setLngLat([lng, lat]);

//  Create the temperature label.
var labelSvg = document.getElementById('label');
var label = new mapboxgl.Marker({ 
    element: labelSvg,
    offset: [0, -27],  //  We have enlarged the icon by 2, so shift the y offset.
}).setLngLat([lng, lat]);

//  Create the geolocation control.
var geolocate = new mapboxgl.GeolocateControl({
    positionOptions: { enableHighAccuracy: true },
    trackUserLocation: true
});

//  Create the map.
var map = new mapboxgl.Map({
    style: 'mapbox://styles/mapbox/dark-v10',
    center: [lng, lat],  //  Longitude, latitude
    zoom:    0, //  17,
    pitch:   0, //  45,
    bearing: 0, //  -17.6,
    container: 'map'
});

//  Test state
var testState = {
    "device": "test1",
    "tmp": 28.95,
    "latitude": 1.274,
    "longitude": 103.81,
    "accuracy": 40.1
};

function updateAccuracy() {
    //  Update the circle that represents geolocation accuracy.  Based on lat, lng, accuracy.

    //  Construct the geojson circle.
    var circle = turf.circle([lng, lat], accuracy, {
        steps: 16, units: 'meters',  //  properties: {foo: 'bar'}
    });
    if (map.getLayer(ACCURACY_LAYER_ID)) {
        //  Remove the circle layer if it exists.
        map.removeLayer(ACCURACY_LAYER_ID);
    }
    if (map.getSource(ACCURACY_LAYER_ID)) {
        //  Remove the accuracy source if it exists.
        map.removeSource(ACCURACY_LAYER_ID);
    }
    //  Add the circle layerand source.
    map.addLayer({
        id: ACCURACY_LAYER_ID,
        type: 'fill',
        source: {
            type: 'geojson',
            data: circle
        },
        layout: {},
        paint: {
            'fill-color': '#803FB1',
            'fill-opacity': 0.2,
        },
    });
}

function updateState(state) {
    //  Given the new server state, update the local state.
    //  Update the temperature.
    if (state.tmp &&
        tmp !== state.tmp) {
        tmp = state.tmp;
        var labelText = document.getElementById('label_text');
        if (labelText) {
            labelText.innerHTML = "" + tmp;
        }
    }
    //  Update the location.
    if (state.latitude && state.longitude && state.accuracy && (
        lat !== state.latitude  ||
        lng !== state.longitude ||
        accuracy !== state.accuracy
    )) {
        lat = state.latitude;
        lng = state.longitude;
        accuracy = state.accuracy;
        map.flyTo({ 
            center: [lng, lat],
            zoom: zoom,
            pitch: pitch,
            bearing: bearing,
            speed: 0.3,  //  Default 1.2
        });
        //  Move the marker and label.
        marker.setLngLat([lng, lat]);
        label.setLngLat([lng, lat]);
        //  Move the accuracy circle.
        updateAccuracy();
    }
}

function pollServer() {
    //  Poll the server for the updated state.
    var url = './pull?device=' + device + '&t=' + new Date().valueOf();
    console.log('pollServer', url);
    if (document.location.protocol == 'file:') {
        return updateState(testState);
    }
    return fetch(url)
    .then(
        function(response) {
            if (response.status !== 200) {
                console.log('pollServer status:', response.status);
                return;
            }
            response.json().then(function(data) {
                console.log('pollServer', data);
                return updateState(data);
            });
        }
    )
    .catch(function(err) {
        console.log('pollServer error:', err);
    });
}

geolocate.on('geolocate', function(data) {
    //  Triggered when geolocated.
    console.log('geolocate', data);
});

map.on('load', function() {
    //  The 'building' layer in the mapbox-streets vector source contains building-height
    //  data from OpenStreetMap.  Insert the layer beneath any symbol layer.
    var layers = map.getStyle().layers;
    var labelLayerId;
    for (var i = 0; i < layers.length; i++) {
        if (layers[i].type === 'symbol' && layers[i].layout['text-field']) {
            labelLayerId = layers[i].id;
            break;
        }
    }

    //  Add the geolocation accuracy circle.
    updateAccuracy();

    //  Add the building layer.
    map.addLayer({
        'id': '3d-buildings',
        'source': 'composite',
        'source-layer': 'building',
        'filter': ['==', 'extrude', 'true'],
        'type': 'fill-extrusion',
        'minzoom': 15,
        'paint': {
            'fill-extrusion-color': '#aaa',
            // use an 'interpolate' expression to add a smooth transition effect to the
            // buildings as the user zooms in
            'fill-extrusion-height': [
                "interpolate", ["linear"], ["zoom"],
                15, 0,
                15.05, ["get", "height"]
            ],
            'fill-extrusion-base': [
                "interpolate", ["linear"], ["zoom"],
                15, 0,
                15.05, ["get", "min_height"]
            ],
            'fill-extrusion-opacity': .6
        }
    }, labelLayerId);

    //  Add the computed geolocation marker.
    marker.addTo(map);
    label.addTo(map);

    //  Add geolocate control to the map.
    map.addControl(geolocate);

    //  Get device from URL parameters.
    var urlParams = new URLSearchParams(window.location.search);
    device = urlParams.get('device');

    //  Set polling timer.
    window.setInterval(pollServer, 10 * 1000);
});

</script>
</html>
